前一篇介紹的Git-如何解決合併衝突,說明了在合併過程中可能遇到的衝突。
成功合併之後也有可能遇到另一個情況,「fast-forward(快轉模式)」。
這是上一篇成功合併的線圖。
把feature分支刪除,並且在master分支上,再重建一個feature分支。
此時,feature分支與master分支,都是同一個版本。
在feature分支:
執行cat,查看a.txt的內容。
將內容改成123。
執行git diff查看修改前後的差異。
commit新版本
feature分支比master分支領先一個版本。
為了讓fast-forward(快轉模式)更明顯,再新增2個檔案。
這樣一來,feature分支會比master分支領先3個版本。
在master分支合併feature分支。
這時會發現,一個訊息:Fast-forward
表示這次的合併,採用了fast-forward(快轉模式)。
那fast-forward(快轉模式)究竟是什麼情況?
查看log
目前,master分支跟feature分支位於同一個版本,這是可以預期的情況,畢竟是master分支合併feature分支。
來看看線圖。
重點來了,跟上一張線圖比較後,會發現master分支從(Merge branch 'feature')版本直接跳到跟feature分支同一個版本(add c.txt)。
線圖並無分岔,而是一條線直接跳上去(黑色)。
這種線圖沒有分岔,而直接跳到最新版的情況,就是fast-forward(快轉模式)
一開始,feature分支與master分支,是同一個版本。
意味著,它們擁有相同的檔案與內容。
然後,feature分支commit了3個新版本。
也就是領先master分支3個版本。
當master分支要合併feature分支時。
它們之間的差異,就只是feature分支比master分支多3個commit而已,其他都是一模一樣。
換句話說,master分支有的feature分支都有。
畢竟它們都是從同一個commit分出去的。
master分支合併feature分支,就等同於合併自己以後的版本。
此時,git就會啟用fast-forward,master分支一口氣跳了3個版本,
到feature分支最新的commit(add c.txt)。
表面上看來,fast-forward合併,並沒有任何問題,結果也都成功合併。
但請仔細思考,分支的意義是什麼?
在軟體開發過程中,會有一條主要分支,其他分支,不管它的任務是什麼,最後,都會併入主要分支。
master分支是主要分支,而feature分支是開發中的分支,master分支直接跳到feature分支的最新commit,是有點奇怪。
這邊要強調,以git的觀點,fast-forward沒有不好,我們是以軟體開發的觀點來討論這個問題。
解決方式就是將fast-forward合併關閉,讓master分支與feature分支的合併,看起來就像是開發中的分支(feature)併入主要分支(master)。
執行git reset --hard ORIG_HEAD,回復合併之前的版本。
master分支回到原本的版本。
再次合併,這次關閉fast-forward。
指令 --no-ff,關閉fast-forward。
執行git merge feature --no-ff。
這次合併訊息,沒有Fast-forward字樣。
確實執行分支合併的動作。
由線圖可以看出,master分支的確合併feature分支,並做了一次commit(Merge branch 'feature')。
合併之後,feature分支可以再繼續開發,再繼續併入master分支。
feature分支再新增檔案。
再次併入master分支。
這樣的線圖非常一目瞭然。
一般來說,我們不會在主要分支,執行開發、修復、測試這些操作,一定都是確認穩定後,再併入主要分支。
從線圖上可以看出哪些分支做了哪些commit,再合併入主要分支。
master分支的黑正方,表示合併後的commit,黑圓點,表示自身的commit,
紅圓點表示feature分支的commit,這樣不是很清楚嗎。
但如果透過fast-forward合併的話,並不會產生合併的commit,且全部的commit都擠在同一條線上,包括master分支,如此一來,我們就很難判斷分支commit的情況。
那到底fast-forward適合用在什麼情況呢?
我們先在GitHub,新建一個repository,並上傳本地專案。
詳細步驟可以參考Git-上傳檔案至遠端儲存庫
上傳成功後可以發現,多了一個origin/master分支,代表遠端儲存庫的master分支,
目前跟本地端的master分支指向同一個版本。
查看前5筆的log
master分支(本地)與origin/master分支(遠端),雖然是不同分支,但它們意義上是相同的,都是master。
所以它們應該要同步才對。
我們來模擬一個多人分工,大家都在origin/master分支開發的情境。
將專案clone下來,跟原本的範例不同位置。
模擬同事A的開發。
詳細步驟可參考Git-git clone 的各種方式
假設同事A修改b.txt後,push至遠端儲存庫。
這時,遠端的origin/master分支有16個commit。
而本地端的master分支有15個commit。
所以遠端的origin/master分支領先本地端的master分支一個版本。
必須得將遠端的origin/master分支下載回來,才能更新版本狀態。
執行git pull,可以下載更新。
但實際上git pull是由兩個命令所組成的:git pull = git fetch + git merge。
也就是說,它會執行兩個動作。
將變更的部分先下載回來(git fetch),再執行合併(git merge)。
執行git fetch
查看線圖。
origin/master分支領先master分支一個版本,這是由同事A所push上去的。
既然已經有新版本了,那就得將master分支合併origin/master分支,我們跟同事A的專案才能同步。
重點注意,這時要採用哪種合併呢?
剛剛我們將fast-forward關閉,是因為master分支與feature分支,意義上是屬於不同的分支,才需要讓線圖分岔。
但目前的情況是,master分支與origin/master分支,意義上都是相同的分支,既然如此,那直接讓master分支一直線上去,是比較合乎邏輯的。線圖分岔,反而會覺得奇怪。
採用fast-forward合併。
讓master分支直接跳到origin/master分支的版本。
使用fast-forward的情況:合併的分支,代表相同的意義。
關閉fast-forward的情況:合併的分支,代表不同的意義。
本文為觀看網路教學的學習筆記。